/*
 * Fine Collection interfaces.
 * 
 * This namespace contains generic interfaces for collections.
 * 
 * Interface naming conventions:
 *   - <c><b>R</b>Collection</c>: interface names started with the \b R character
 *                                represent read-only collection,
 *   - <c><b>W</b>Collection</c>: interface names started with the \b W character
 *                                represent writeable collection.
 * 
 * 
 */
using System;
using System.Text;



namespace FineCollection.Intf
{
    /// <summary>
    /// Generic collection (read only interface).
    /// </summary>
    /// <typeparam name="T">type of an item.</typeparam>
    /// 
    /// <seealso cref="RCollection_Ext"/>
    public interface RCollection<T>
        : System.Collections.Generic.IEnumerable<T>
    {

        /// <summary>
        /// Count of items in the collection.
        /// </summary>
        int Count
        {
            get;
        }


        /// <summary>
        /// Checks whether the collection is empty.
        /// </summary>
        bool IsEmpty
        {
            get;
        }


        /// <summary>
        /// Checks whether the collection has at least one item.
        /// </summary>
        bool IsNotEmpty
        {
            get;
        }


        /// <summary>
        /// Looks for the first item that meets the specified predicate.
        /// </summary>
        /// <param name="predicate">item predicate.</param>
        /// <returns>found item, 
        ///          or a default value of the <typeparamref name="T"/> if not found.</returns>
        /// <seealso cref="Find"/>
        T this[Predicate<T> predicate]
        { 
            get;
        }


        /// <summary>
        /// Looks for the first item that meets the specified predicate.
        /// </summary>
        /// <param name="predicate">item predicate.</param>
        /// <param name="defaultValue">default value, 
        ///                            that will be used in case 
        ///                            when no items meet the specified <paramref name="predicate"/>.</param>
        /// <returns>found item, or the specified <paramref name="defaultValue"/> if not found.</returns>
        T Find(Predicate<T> predicate, T defaultValue);


        /// <summary>
        /// Creates a read-only iterator.
        /// </summary>
        /// <returns></returns>
        RIterator<T> TakeIterator();

    }


    /// <summary>
    /// Extension functions for <see cref="RCollection{T}"/>.
    /// </summary>
    public static class RCollection_Ext
    {
        
        ///<summary>
        /// Returns the array representation of the collection.
        ///</summary>
        ///<param name="collection">collection to get array of items.</param>
        ///<returns>an array of items (with order preserving);
        ///         an empty array when the given collection is ampty;
        ///         a null when the given argument is null.</returns>
        public static T[] ToArray<T>(this RCollection<T> collection)
        {
            if (collection == null)
                return null;

            int n = collection.Count;
            T[] array = new T[n];

            RIterator<T> it = collection.TakeIterator();  
            it.Next(); int k = 0;
            while (it.Where < +1 && k < n)
            {
                array[k] = it.Current;
                it.Next(); k++;
            }

            return array;
        }


        /// <summary>
        /// Checks whether the collection contains the specified item. 
        /// This function uses <c>Equals()</c> to perform comparison.
        /// The complexity of this operation is <i>o(n)</i>.
        /// </summary>
        /// <typeparam name="T">type of items.</typeparam>
        /// <param name="collection">collection to search in. May be null or empty.</param>
        /// <param name="item">The item to search.</param>
        /// <returns><c>true</c> if the item exists in the collection.</returns>
        public static bool Contains<T>(this RCollection<T> collection, T item)
        {
            if (collection == null || collection.IsEmpty)
                return false;

            RIterator<T> it = collection.TakeIterator();
            while (it.Next())
                if (it.Current.Equals(item))
                    return true;

            return false;            
        }


        /// <summary>
        /// Make a string or a text based on the collection content.
        /// Really, it converts each item to a string 
        /// and join all strings with the specified separator.
        /// </summary>
        /// <remarks>
        /// An empty collection produces an empty string,
        /// a null collection produces a null.
        /// </remarks>
        /// <typeparam name="T">type of items.</typeparam>
        /// <param name="collection">collection which content to convert to a text.</param>
        /// <param name="itemToString">convertor for each item.</param>
        /// <param name="separator">separator.</param>
        /// <returns>the result string or text.</returns>
        public static string ToString<T>(this RCollection<T> collection,
                                         Func<T, string> itemToString,
                                         string separator)
        {
            if (collection == null)
                return null;
            if (collection.IsEmpty)
                return string.Empty;

            StringBuilder sb = new StringBuilder();
            bool first = true;
            RIterator<T> it = collection.TakeIterator();
            while (it.Next())
            {
                if (first)
                    first = false;
                else
                    sb.Append(separator);

                sb.Append(itemToString(it.Current));
            }

            return sb.ToString();
        }

    }

    
}
